package com.ybwh.springboot2.util;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Preconditions;
import com.google.common.collect.Sets;
import com.ybwh.springboot2.common.RespData;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;


import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * httpweb 工具类
 * </p>
 *
 * @author ybwh
 * @since 2019年5月17日 下午2:28:17
 */
@Slf4j
public class HttpWebUtil {
    private HttpWebUtil() {
    }

    private boolean verifyWhiteListURL(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String urlWhiteList = "/login";
        String originalUri = request.getRequestURI();
        log.debug("URL白名单判断,originalUri:{}", originalUri);
        if (urlMatchs(urlWhiteList, originalUri)) {
            log.debug("URL白名单提前返回..");
            return true;
        }
        return false;
    }


    public static Boolean urlMatchs(String urlWhiteList, String originalUri) {
        if (StringUtils.isNotBlank(originalUri) && StringUtils.isNotBlank(urlWhiteList)) {
            String[] urls = originalUri.split("\\?");
            String prefixOriginalUrl = urls[0];
            AntPathMatcher matcher = new AntPathMatcher();
            Set<String> urlWhiteLists = Sets.newHashSet(urlWhiteList.split(","));
            for (String curUrl : urlWhiteLists) {
                if (StringUtils.isBlank(curUrl)) {
                    continue;
                }
                String urlPrefix = "/*-web";
                if (curUrl.contains("-web/")) {
                    urlPrefix = "";
                }
                if (matcher.match(urlPrefix + curUrl, prefixOriginalUrl)) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }


    /**
     * 获取url中的参数值
     *
     * @param paramStr url中参数部分字符串，不包含问号
     * @param paramKey 参数名
     * @return 参数值
     */
    public static String getUrlParam(String paramStr, String paramKey) {
        Preconditions.checkArgument(StringUtils.isNotBlank(paramKey));
        return getUrlParamMap(paramStr).get(paramKey);
    }

    /**
     * 获取url中的参数对
     *
     * @param paramStr url中参数部分字符串，不包含问号
     * @return 参数名 -> 参数值
     */
    public static Map<String, String> getUrlParamMap(String paramStr) {
        if (StringUtils.isBlank(paramStr)) {
            return Collections.emptyMap();
        }


        String[] paramArr = paramStr.split("&");
        Map<String, String> paramMap = new HashMap<>(paramArr.length);
        for (String s : paramArr) {
            if (-1 == s.indexOf("=")) {
                continue;
            }

            String[] pArr = s.split("=");
            paramMap.put(pArr[0], pArr[1]);
        }

        return paramMap;
    }


    /**
     * 向前端返回需要重新登录逻辑
     *
     * @param handlerMethod
     * @param response
     * @throws IOException
     */
    public static void respRequireLogin(HandlerMethod handlerMethod, HttpServletResponse response) throws IOException {
        if (isAjax(handlerMethod)) {
            try {
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print(JSON.toJSONString(RespData.reLoginResp()));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } else {
            response.sendRedirect("login");
        }
    }


    /**
     * 是否是ajax请求
     *
     * @param handlerMethod
     * @return
     */
    public static boolean isAjax(HandlerMethod handlerMethod) {
        ResponseBody responseBody = handlerMethod.getMethodAnnotation(ResponseBody.class);
        if (null != responseBody) {
            return true;
        }

        RestController restController = handlerMethod.getBeanType().getAnnotation(RestController.class);
        if (null != restController) {
            return true;
        }

        return false;
    }


    /**
     * 判断请求是否为Ajax
     *
     * @param request HttpServletRequest
     * @return true or false
     */
    public static boolean isAjaxRequest(HttpServletRequest request) {
        String ajaxPostReqHead = request.getHeader("X-Requested-With");
        String ajaxGetReqHead = request.getHeader("RequestType");
        if (ajaxPostReqHead != null && !"".equals(ajaxPostReqHead) && "XMLHttpRequest".equals(ajaxPostReqHead)
                || (ajaxGetReqHead != null && !"".equals(ajaxGetReqHead) && "ajax".equalsIgnoreCase(ajaxGetReqHead))) {
            return true;
        } else {
            return false;
        }
    }

    public static String getIPAddress(HttpServletRequest request) {
        String ip = null;

        //X-Forwarded-For：Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP：apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP：weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP：有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }

        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP：nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

}
